﻿import spade
from page_dl import init_crawlers
from Queue import Queue
from SimpleSyncSet import SimpleSyncSet
import time

_show_function_calls = False


class MyPeriodicBehaviour(spade.Behaviour.PeriodicBehaviour):
  def __init__(self, period, timestart=0):
    # timestart w spade jest ustawiany na wartosc, a nie time.time() + wartosc, wiec to przerobilem, zeby bylo czytelniej
    spade.Behaviour.PeriodicBehaviour.__init__(self, period, time.time() + timestart)


class MakeAgentList(MyPeriodicBehaviour): # zachowanie tworzace liste agentow
  def __init__(self, period, timestart, service_name, setter):
    self.service_name = service_name
    self.setter = setter
    self.template = spade.DF.DfAgentDescription()
    sd = spade.DF.ServiceDescription()
    sd.setType(self.service_name)
    self.template.addService(sd)
    print '#', self.template, '#'
    MyPeriodicBehaviour.__init__(self, period, timestart)

  def _onTick(self):
    if _show_function_calls:
      print '\t+MakeAgentList'
    res = self.myAgent.searchService(self.template)
    res = map(lambda a: a.getName(), res)
    res.remove(self.myAgent.getName())
    self.setter(res)
##      print 'found agents:'
##      for a in res:
##        print a
    if _show_function_calls:
      print '\t-MakeAgentList'


  ##################################################################
  ## CrawlerAgent                                                 ##
  ##################################################################

class CrawlerAgent(spade.Agent.Agent): # podstawowy agent z consistent hashing, bez dodatkowego LB
  class ReceiveUrlsBehav(spade.Behaviour.Behaviour): # zachowanie odbierajace urle
    def _process(self):
      msg = None
      msg = self._receive()
      if msg:
        if _show_function_calls:
          print '\t+ReceiveUrlsBehav'
        urls_s = msg.getContent()
##        print '#',msg,'#'
        urls = urls_s.split(' ')
        print 'I got urls:', len(urls)
        for url in urls:
          if url not in self.myAgent.visited_set:
            self.myAgent.url_queue.put(url)
        if _show_function_calls:
          print '\t-ReceiveUrlsBehav'
  ##################################################################
  class SendConsistentHashing(MyPeriodicBehaviour):
    def _onTick(self):
      if _show_function_calls:
        print '\t+SendConsistentHashing'
      if self.myAgent.agents == []:
        return
      for aname in self.myAgent.urls.keys():
        if self.myAgent.urls[aname] != []:
          receiver = spade.AID.aid(name=aname, addresses=['xmpp://' + aname])
          msg = spade.ACLMessage.ACLMessage()
          msg.setPerformative('inform')
          msg.setOntology(self.myAgent.cons_hash_service_name)
          msg.addReceiver(receiver)
          urls, self.myAgent.urls[aname] = self.myAgent.urls[aname], []
          urls_s = ' '.join(urls)
          msg.setContent(urls_s)
          self.myAgent.send(msg)
      if _show_function_calls:
        print '\t-SendConsistentHashing'
  ##################################################################
  class SendLoadBehaviour(spade.Behaviour.Behaviour):
    '''
    Wysylanie informacji o obciazeniu
    '''
    def _process(self):
      msg = None
      msg = self._receive()
      if msg:
        tm = msg.getContent()
        if _show_function_calls:
          print '\t+SendingLoad to stats'
        try:
          avg_urls_per_tick = str(self.myAgent.avg_urls_per_tick)
        except Exception, e:
          avg_urls_per_tick = ""
        qsize = str(self.myAgent.url_queue.qsize())
        load = avg_urls_per_tick + "#" + qsize + "#" + tm
        rmsg = msg.createReply()
        rmsg.setContent(load)
        rmsg.setPerformative('inform')
        rmsg.setOntology('statistics')
        self.myAgent.send(rmsg)
        if _show_function_calls:
          print '\t-SendingLoad to stats'

  ##################################################################
  def __init__(self, agentjid, password, port=5222, debug=[], p2p=False, num=1, fname=None):
    self.num = num
    self.fname = fname
    self.make_list_timestart = 1
    self.lb_timestart = 3
    self.behav_period = 10
    spade.Agent.Agent.__init__(self, agentjid, password, port, debug, p2p)
  ##################################################################
  def add_service(self, stype):
    sd = spade.DF.ServiceDescription()
    sd.setName(stype + ' service')
    sd.setType(stype)
    dfd = spade.DF.DfAgentDescription()
    dfd.getServices()
    dfd.addService(sd)
    dfd.setAID(self.getAID())
    self.registerService(dfd)
    print 'registered'
  ##################################################################
  def visited_url_handler(self, url):
    pass
  ##################################################################
  def set_agents(self, agents):
    self.agents = agents
    print '#', self.agents
  ##################################################################
  def _setup(self):
    # cons_hash - czy uzywac consistent hashing
    # num - ilosc watkow
    # fname - nazwa pliku z poczatkowym zbiorem adresow, jesli zostanie None, to zbior domyslny z page_dl.py
    print self.getName()
    self.agents = []
    self.urls = {}
    self.cons_hash_service_name = 'url_transfer'

    template = spade.Behaviour.ACLTemplate()
    template.setPerformative('query-ref')
    template.setOntology('statistics')
    mt = spade.Behaviour.MessageTemplate(template)
    b = self.SendLoadBehaviour()
    self.addBehaviour(b, mt)

    b = self.SendConsistentHashing(self.behav_period, self.lb_timestart)
    self.addBehaviour(b)

    template = spade.Behaviour.ACLTemplate()
    template.setPerformative('inform')
    template.setOntology(self.cons_hash_service_name)
    mt = spade.Behaviour.MessageTemplate(template)
    b = self.ReceiveUrlsBehav()
    self.addBehaviour(b, mt)

    b = MakeAgentList(self.behav_period, self.make_list_timestart, self.cons_hash_service_name, self.set_agents)
    self.addBehaviour(b)

    self.add_service(self.cons_hash_service_name)

    self.url_queue = Queue()
    self.visited_set = SimpleSyncSet()

    init_crawlers(self.url_queue, self.visited_set, self, self.num, self.fname)
